﻿// LZWCode.cpp: implementation of the LZWCode class.
//
//////////////////////////////////////////////////////////////////////

#include "stdafx.h"
#include "BiShe.h"
#include "LZWCode.h"

#ifdef _DEBUG
#undef THIS_FILE
static char THIS_FILE[]=__FILE__;
#define new DEBUG_NEW
#endif

//////////////////////////////////////////////////////////////////////
// Construction/Destruction
//////////////////////////////////////////////////////////////////////

LZWCode::LZWCode()
{
	m_TabLen=0;
	InitCompTable();
}

/**************************************************************
函数名：~LZWCode
功能：该函数为析构函数，释放动态创建的内存
入口参数：无
出口参数：无
说明：释放编译表所占的内存间
 **************************************************************/
LZWCode::~LZWCode()
{
	for(unsigned short i=256;i<m_CurTabSize;i++)
		free(m_Tab[i].string);
}

/*说实在的到写这代码的时候我对于如何初始化编译表一点想法都没有，
  初始化多少项我真的不知道，但任务摆在那里，时间又紧迫，暂且只
  初始化可见的根字符表项吧！*/
/**************************************************************
函数名：InitCompTable
功能：初始化编译表
入口参数：root:编译表的头部
出口参数：
说明：初始化编译表为256项，因为不指针对字符编码，这样具有广泛性，
	可能对字节流编码
 **************************************************************/
void LZWCode::InitCompTable()
{
	unsigned short ind=0;
	char *str=(char*)malloc(512);
	for(ind=0;ind<256;ind++)
	{
		str[ind*2]=(char)ind;
		str[ind*2+1]='\0';

		m_Tab[ind].string=&str[2*ind];
		m_Tab[ind].index=ind;
	}
	m_CurTabSize=256;
}

/**************************************************************
函数名：AddToTable
功能：向编译表中添加一个字符串
入口参数：str:字符串地址
出口参数：taNew添加表项的地址
说明：如果添加表项成功则返回其地址，否则返回NULL
 **************************************************************/
bool LZWCode::AddToTable(char *str)
{
	if(m_CurTabSize>=4095)
		return true;
	char *cTemp=(char*)malloc(strlen(str)+1);
	if(!cTemp)
		return false;
	strcpy(cTemp,str);
	m_Tab[m_CurTabSize].string=cTemp;
	//m_Tab[m_CurTabSize].index=m_CurTabSize;
	m_CurTabSize++;
	return true;
}

/**************************************************************
函数名：IsInTable
功能：检查一个字符串是否在编译表中
入口参数：str:字符串首地址
出口参数：ind:字符串在编译表中的索引值
说明：如果给定字串在表中找到则返回其索引值，否则返回NULL值
 **************************************************************/
unsigned int LZWCode::IsInTable(char *str)
{
	//unsigned int ind=0;//所查找的字符串在链表的索引
	unsigned int i=0;
	if(strlen(str)>1)
		i=256;
	for(;i<m_CurTabSize;i++)
		if(!(strcmp(m_Tab[i].string,str)))
			return i;
	 return 0;
}


/**************************************************************
函数名：IsInTable
功能：检查一个字符串是否在编译表中
入口参数：str:字符串首地址
出口参数：ind:字符串在编译表中的索引值
说明：如果给定字串在表中找到则返回其索引值，否则返回NULL值
 **************************************************************/
char* LZWCode::IsInTable(unsigned short ind)
{
    //所查找的字符串在链表的索引
	if(ind<m_CurTabSize)
		return m_Tab[ind].string;
	return NULL;
}

/**************************************************************
函数名：IsInTable
功能：检查一个字符串是否在编译表中
入口参数：str:字符串首地址
出口参数：ind:字符串在编译表中的索引值
说明：如果给定字串在表中找到则返回其索引值，否则返回NULL值
 **************************************************************/
void LZWCode::Compress(FILE *inf, FILE *outf)
{
	 unsigned short ind1=0;
	 char prefix[4096];
	 char sufix[2]={'\0','\0'};
	 char temp[4096];
	 memset(prefix,'\0',4096);
	 memset(temp,'\0',4096);
	 
	 fread(prefix,1,1,inf);
	 
	 while(!feof(inf))
	 {	 	  
		 fread(sufix,1,1,inf);
		 strcpy(temp,prefix);
		 strncat(temp,sufix,1);
		 if((IsInTable(temp)))
		 {		 	
			strcat(prefix,sufix);		
		 }
		 else
		 {	 
			ind1=IsInTable(prefix);
  			fwrite(&ind1,sizeof(unsigned short),1,outf);
  			AddToTable(temp);
 			strcpy(prefix,sufix); 	
		 }
	 }
	 //ind1=IsInTable(prefix);
	 //fwrite(&ind1,sizeof(unsigned short),1,outf);
}

/**************************************************************
函数名：IsInTable
功能：检查一个字符串是否在编译表中
入口参数：str:字符串首地址
出口参数：ind:字符串在编译表中的索引值
说明：如果给定字串在表中找到则返回其索引值，否则返回NULL值
 **************************************************************/
void LZWCode::DeCompress(FILE *inf, FILE *outf)
{
	 unsigned short code=0;
	 unsigned short oldCode=0;
	 char prefix[4096];
	 char *temp=NULL;
	 memset(prefix,'\0',4096);
	 
	 fread(&code,sizeof(unsigned short),1,inf);
     if((temp=IsInTable(code))){

		 fwrite(temp,strlen(temp),1,outf);
		 oldCode=code;
	 }
	 while(!feof(inf))
	 {	 
		 fread(&code,sizeof(unsigned short),1,inf);
		 if((temp=IsInTable(code))){

			fwrite(temp,strlen(temp),1,outf);
			strcpy(prefix,IsInTable(oldCode));
			strncat(prefix,IsInTable(code),1);
			AddToTable(prefix);
			oldCode=code;
  			
		 }

		 else{
			strcpy(prefix,IsInTable(oldCode));
			strncat(prefix,IsInTable(oldCode),1);
			fwrite(prefix,strlen(prefix),1,outf);
			AddToTable(prefix);
			oldCode=code;	
		 }
	 }
	 temp=IsInTable(oldCode);
	 fwrite(temp,strlen(temp),1,outf);
}

unsigned int LZWCode::GetTabLen()
{
	return m_CurTabSize;
}
